package reflects

import (
	"fmt"
	"reflect"
)

// SetStructFieldVal  设置结构体字段值
// structPtr  结构体指针
// fieldName  字段名称
// val  目标值
func SetStructFieldVal(structPtr interface{}, fieldName string, val interface{}) {

	if !IsPointerToStruct(structPtr) {
		panic("structPtr is not  a pointer to struct")
	}

	if IsZeroValue(structPtr) {
		panic("The parameter structPtr is zero")
	}

	rType := reflect.TypeOf(structPtr)
	rVal := reflect.ValueOf(structPtr)
	if rType.Kind() == reflect.Ptr {
		// 传入的structPtr是指针，需要.Elem()取得指针指向的value
		rType = rType.Elem()
		rVal = rVal.Elem()
	} else {
		panic("The parameter structPtr must be ptr to struct")
	}

	_, ok := rType.FieldByName(fieldName)
	if !ok {
		panic("The field " + fieldName + " cannot found")
	}

	f := rVal.FieldByName(fieldName)
	f.Set(reflect.ValueOf(val))
}

// IsStruct 判断变量是否结构体
func IsStruct(v interface{}) bool {

	fmt.Printf("--------%+v \n", reflect.TypeOf(v).Kind())
	return reflect.TypeOf(v).Kind() == reflect.Struct
}

// IsPtr 判断变量是否指针
func IsPtr(v interface{}) bool {
	return reflect.TypeOf(v).Kind() == reflect.Ptr
}

// IsPointerToStruct 判断变量是否是指向结构体的指针
func IsPointerToStruct(v interface{}) bool {
	// 获取变量的反射类型对象
	t := reflect.TypeOf(v)
	//fmt.Printf("--------------%+v \n", t.Kind())
	// 检查变量是否是指针类型
	if t.Kind() != reflect.Ptr {
		return false
	}
	// 获取指针指向的元素类型
	elemType := t.Elem()
	//fmt.Printf("--------------%+v \n", elemType.Kind())
	// 检查元素类型是否为结构体类型
	return elemType.Kind() == reflect.Struct
}

// isZeroStructOrArray 是否是零值结构体或数组
func isZeroStructOrArray(val reflect.Value) bool {
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		if !IsZeroValue(field.Interface()) { // 递归检查每个字段或元素是否为0值
			return false
		}
	}
	return true // 所有字段或元素都是零值时返回true
}

func IsNil(x interface{}) bool {
	if nil == x {
		return true
	}
	rv := reflect.ValueOf(x)
	return rv.Kind() == reflect.Ptr && rv.IsNil()

}

// IsZeroValue 是否是零值
func IsZeroValue(i interface{}) bool {
	value := reflect.ValueOf(i)
	switch value.Kind() {
	//case reflect.Array, reflect.Struct:
	//	return isZeroStructOrArray(value)
	case reflect.String:
		return value.Len() == 0
	case reflect.Bool:
		return !value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return value.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return value.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return value.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return value.IsNil()
	}

	return reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface())
}
